/**
 * View World Working.
 *
 * Released under Apache License, Version 2.0.
 */

package bsp.eclair.simplelinechart.viewworld;

import android.util.Log;

public class ViewWorldWorking
{
	protected float mWorldXMin, mWorldYMin, mWorldXMax, mWorldYMax;
	protected float mOriginX, mOriginY;
	protected int mViewXMin, mViewYMin, mViewXMax, mViewYMax;
	protected int mLeftPadding, mTopPadding, mRightPadding, mBottomPadding; 
	
	/**
	 * Default constructor.
	 * Create with default world object coordinate values, namely 0 to 1.
	 * View object coordinate values are default, namely 0 to 100.
	 * Origin is at 0,0 of world object.
	 * Padding values are zero.
	 */
	public ViewWorldWorking()
	{
		mWorldXMin = mWorldYMin = 0;
		mWorldXMax = mWorldYMax = 1;
		
		mViewXMin = mViewYMin = 0;
		mViewXMax = mViewYMax = 100;
		
		mOriginX = mOriginY = 0;
		
		mLeftPadding = mTopPadding = mRightPadding = mBottomPadding = 0;
	}
	
	/**
	 * Create with default world object coordinate values, namely 0 to 1.
	 * View object coordinate values are as provided.
	 * Origin is at 0,0 of world object.
	 * Padding values are zero.
	 * 
	 * @param viewStartX
	 * @param viewStartY
	 * @param viewEndX
	 * @param viewEndY
	 */
	public ViewWorldWorking(int viewStartX, int viewStartY, int viewEndX, int viewEndY)
	{
		mWorldXMin = mWorldYMin = 0;
		mWorldXMax = mWorldYMax = 1;
		
		mViewXMin = viewStartX;
		mViewYMin = viewStartY;
		mViewXMax = viewEndX;
		mViewYMax = viewEndY;
		
		mOriginX = mOriginY = 0;
		
		mLeftPadding = mTopPadding = mRightPadding = mBottomPadding = 0;
	}
	
	/**
	 * Create with default view object coordinate values, namely 0 to 100.
	 * World object coordinate values are as provided.
	 * Origin is at 0,0 of world object.
	 * Padding values are zero.
	 * 
	 * @param worldStartX
	 * @param worldStartY
	 * @param worldEndX
	 * @param worldEndY
	 */
	public ViewWorldWorking(float worldStartX, float worldStartY, float worldEndX, float worldEndY)
	{
		mWorldXMin = worldStartX;
		mWorldYMin = worldStartY;
		mWorldXMax = worldEndX;
		mWorldYMax = worldEndY;
		
		mViewXMin = mViewYMin = 0;
		mViewXMax = mViewYMax = 100;
		
		mOriginX = mOriginY = 0;
		
		mLeftPadding = mTopPadding = mRightPadding = mBottomPadding = 0;
	}
	
	/**
	 * Initialize object using coordinate values provided.
	 * Origin is at 0,0 of world object.
	 * Padding values are zero.
	 * 
	 * @param worldStartX
	 * @param worldStartY
	 * @param worldEndX
	 * @param worldEndY
	 * @param viewStartX
	 * @param viewStartY
	 * @param viewEndX
	 * @param viewEndY
	 */
	public ViewWorldWorking(float worldStartX, float worldStartY, float worldEndX, float worldEndY, int viewStartX, int viewStartY, int viewEndX, int viewEndY)
	{
		mWorldXMin = worldStartX;
		mWorldYMin = worldStartY;
		mWorldXMax = worldEndX;
		mWorldYMax = worldEndY;
		
		mViewXMin = viewStartX;
		mViewYMin = viewStartY;
		mViewXMax = viewEndX;
		mViewYMax = viewEndY;
		
		mOriginX = mOriginY = 0;
		
		mLeftPadding = mTopPadding = mRightPadding = mBottomPadding = 0;
	}
	
	/**
	 * Initialize using values provided.
	 * Padding values are zero.
	 * 
	 * @param worldStartX
	 * @param worldStartY
	 * @param worldEndX
	 * @param worldEndY
	 * @param originX
	 * @param originY
	 * @param viewStartX
	 * @param viewStartY
	 * @param viewEndX
	 * @param viewEndY
	 */
	public ViewWorldWorking(float worldStartX, float worldStartY, float worldEndX, float worldEndY, float originX, float originY, int viewStartX, int viewStartY, int viewEndX, int viewEndY)
	{
		mWorldXMin = worldStartX;
		mWorldYMin = worldStartY;
		mWorldXMax = worldEndX;
		mWorldYMax = worldEndY;
		
		mViewXMin = viewStartX;
		mViewYMin = viewStartY;
		mViewXMax = viewEndX;
		mViewYMax = viewEndY;
		
		mOriginX = originX;
		mOriginY = originY;
		
		mLeftPadding = mTopPadding = mRightPadding = mBottomPadding = 0;
	}
	
	/**
	 * Initialize using values provided.
	 * 
	 * @param worldStartX
	 * @param worldStartY
	 * @param worldEndX
	 * @param worldEndY
	 * @param originX
	 * @param originY
	 * @param viewStartX
	 * @param viewStartY
	 * @param viewEndX
	 * @param viewEndY
	 * @param leftPadding
	 * @param topPadding
	 * @param rightPadding
	 * @param bottomPadding
	 */
	public ViewWorldWorking(float worldStartX, float worldStartY, float worldEndX, float worldEndY, float originX, float originY, int viewStartX, int viewStartY, int viewEndX, int viewEndY, int leftPadding, int topPadding, int rightPadding, int bottomPadding)
	{
		mWorldXMin = worldStartX;
		mWorldYMin = worldStartY;
		mWorldXMax = worldEndX;
		mWorldYMax = worldEndY;
		
		mLeftPadding = leftPadding;
		mTopPadding = topPadding;
		mRightPadding = rightPadding;
		mBottomPadding = bottomPadding;
		
		mViewXMin = viewStartX + mLeftPadding;
		mViewYMin = viewStartY + mTopPadding;
		mViewXMax = viewEndX - mRightPadding;
		mViewYMax = viewEndY - mBottomPadding;
		
		mOriginX = originX;
		mOriginY = originY;
	}
	
	/**
	 * Get dimensions of world object.
	 * 
	 * @return
	 */
	public RectFloat getWorldDimensions()
	{
		RectFloat rf = new RectFloat();
		rf.left = mWorldXMin;
		rf.top = mWorldYMin;
		rf.right = mWorldXMax;
		rf.bottom = mWorldYMax;
		
		return rf;
	}
	
	/**
	 * Update the dimensions of the world using absolute values.
	 * 
	 * @param minx
	 * @param miny
	 * @param maxx
	 * @param maxy
	 * @param originX
	 * @param originY
	 */
	public void updateWorldDimensions(float minx, float miny, float maxx, float maxy, float originX, float originY)
	{
		mWorldXMin = minx;
		mWorldYMin = miny;
		mWorldXMax = maxx;
		mWorldYMax = maxy;
		
		mOriginX = originX;
		mOriginY = originY;
	}
	
	/**
	 * Update the dimensions of the world using offset values.
	 * 
	 * @param offsetx
	 * @param offsety
	 */
	public void updateWorldDimensionsByOffset(float offsetx, float offsety)
	{
		mWorldXMin += offsetx;
		mWorldYMin += offsety;
		mWorldXMax += offsetx;
		mWorldYMax += offsety;
		
		mOriginX += offsetx;
		mOriginY += offsety;
	}
	
	/**
	 * Get origin.
	 * @return
	 */
	public Point2DFloat getWorldOrigin()
	{
		Point2DFloat origin = new Point2DFloat();
		origin.mX = mOriginX;
		origin.mY = mOriginY;
		
		return origin;
	}
	
	/**
	 * Get dimensions of view.
	 * 
	 * @return
	 */
	public RectInt getViewDimensions()
	{
		RectInt rf = new RectInt();
		rf.left = mViewXMin;
		rf.top = mViewYMin;
		rf.right = mViewXMax;
		rf.bottom = mViewYMax;
		
		return rf;
	}
	
	/**
	 * Update dimensions of view using absolute values.
	 * 
	 * @param minx
	 * @param miny
	 * @param maxx
	 * @param maxy
	 */
	public void updateViewDimensions(int minx, int miny, int maxx, int maxy)
	{
		mViewXMin = minx;
		mViewYMin = miny;
		mViewXMax = maxx;
		mViewYMax = maxy;
	}
	
	/**
	 * Update dimensions of view using absolute values.
	 * Also update values of padding.
	 * 
	 * @param minx
	 * @param miny
	 * @param maxx
	 * @param maxy
	 * @param leftPadding
	 * @param topPadding
	 * @param rightPadding
	 * @param bottomPadding
	 */
	public void updateViewDimensions(int minx, int miny, int maxx, int maxy, int leftPadding, int topPadding, int rightPadding, int bottomPadding)
	{
		mViewXMin = minx + leftPadding;
		mViewYMin = miny + topPadding;
		mViewXMax = maxx - rightPadding;
		mViewYMax = maxy - bottomPadding;
	}
	
	/**
	 * Update dimensions of view using offset values.
	 * @param offsetx
	 * @param offsety
	 */
	public void updateViewDimensionsByOffset(int offsetx, int offsety)
	{
		mViewXMin += offsetx;
		mViewYMin += offsety;
		mViewXMax += offsetx;
		mViewYMax += offsety;
	}
	
	/**
	 * Convert x coordinate value in world to view which is in quadrant 4 - x increasing left, y increasing down
	 * @param worldX
	 * @return
	 */
	public int convertToViewXQuadrant4(double worldX)
	{
		int retVal = 0;
		
		retVal = (int) (( (mViewXMax - mViewXMin) / (mWorldXMax - mWorldXMin) ) * (worldX  - mWorldXMin) + mViewXMin);
		
		return retVal;
	}
	
	/**
	 * Convert y coordinate value in world to view which is in quadrant 4 - x increasing left, y increasing down
	 * @param worldX
	 * @return
	 */
	public int convertToViewYQuadrant4(double worldY)
	{
		int retVal = 0;
		
		retVal = (int) (( (mViewYMax - mViewYMin) / (mWorldYMax - mWorldYMin) ) * (worldY  - mWorldYMin) + mViewYMin);
		
		return retVal;
	}
	
	/**
	 * Convert x and y coordinate value in world to view which is in quadrant 4 - x increasing left, y increasing down
	 * @param worldX
	 * @return
	 */
	public Point2DInt convertToViewQuadrant4(double worldX, double worldY)
	{
		Point2DInt retPt = new Point2DInt();
		
		retPt.mX = (int) (( (mViewXMax - mViewXMin) / (mWorldXMax - mWorldXMin) ) * (worldX  - mWorldXMin) + mViewXMin);
		retPt.mY = (int) (( (mViewYMax - mViewYMin) / (mWorldYMax - mWorldYMin) ) * (worldY - mWorldYMin) + mViewYMin);
		
		return retPt;
	}
	
	/**
	 * Convert 2d point value in world to view which is in quadrant 1 - x increasing left, y increasing down
	 * @param worldX
	 * @return
	 */
	public Point2DInt convertToViewQuadrant4(Point2DFloat pt)
	{
		Point2DInt retPt = new Point2DInt();
		
		retPt.mX = (int) (( (mViewXMax - mViewXMin) / (mWorldXMax - mWorldXMin) ) * (pt.mX  - mWorldXMin) + mViewXMin);
		retPt.mY = (int) (( (mViewYMax - mViewYMin) / (mWorldYMax - mWorldYMin) ) * (pt.mY  - mWorldYMin) + mViewYMin);
		
		//Log.d("ViewWorldWorking", "convertToViewQuadrant4 - pt.x: " + pt.mX + ", pt.y: " + pt.mY + ", retPt.x: " + retPt.mX + ", retPt.y: " + retPt.mY);
		
		return retPt;
	}
	
	/**
	 * Convert rectangle value in world to view which is in quadrant 1 - x increasing left, y increasing down
	 * @param worldX
	 * @return
	 */
	public RectInt convertToViewQuadrant4(RectFloat world)
	{
		RectInt ret = new RectInt();
		
		ret.left = (int) (( (mViewXMax - mViewXMin) / (mWorldXMax - mWorldXMin) ) * (world.left  - mWorldXMin) + mViewXMin);
		ret.top = (int) (( (mViewYMax - mViewYMin) / (mWorldYMax - mWorldYMin) ) * (world.top - mWorldYMin) + mViewYMin);
		
		ret.right = (int) (( (mViewXMax - mViewXMin) / (mWorldXMax - mWorldXMin) ) * (world.right  - mWorldXMin) + mViewXMin);
		ret.bottom = (int) (( (mViewYMax - mViewYMin) / (mWorldYMax - mWorldYMin) ) * (world.bottom - mWorldYMin) + mViewYMin);
		
		return ret;
	}
	
	/**
	 * Convert x coordinate value in world to view which is in quadrant 1 - x increasing left, y increasing up
	 * @param worldX
	 * @return
	 */
	public int convertToViewYQuadrant1(double worldY)
	{
		int retVal = 0;

		worldY = mWorldYMax - (worldY * mWorldYMax);
		retVal = (int) (( (mViewYMax - mViewYMin) / (mWorldYMax - mWorldYMin) ) * (worldY  - mWorldYMin) + mViewYMin);
		
		return retVal;
	}

	/**
	 * Convert x and y coordinate value in world to view which is in quadrant 1 - x increasing left, y increasing up
	 * @param worldX
	 * @return
	 */
	public Point2DInt convertToViewQuadrant1(double worldX, double worldY)
	{
		Point2DInt retPt = new Point2DInt();
		
		retPt.mX = (int) (( (mViewXMax - mViewXMin) / (mWorldXMax - mWorldXMin) ) * (worldX  - mWorldXMin) + mViewXMin);
		worldY = mWorldYMax - (worldY * mWorldYMax);
		retPt.mY = (int) (( (mViewYMax - mViewYMin) / (mWorldYMax - mWorldYMin) ) * (worldY - mWorldYMin) + mViewYMin);
		
		return retPt;
	}
	
	/**
	 * Convert 2d point value in world to view which is in quadrant 1 - x increasing left, y increasing up
	 * @param worldX
	 * @return
	 */
	public Point2DInt convertToViewQuadrant1(Point2DFloat pt)
	{
		Point2DInt retPt = new Point2DInt();
		
		retPt.mX = (int) (( (mViewXMax - mViewXMin) / (mWorldXMax - mWorldXMin) ) * (pt.mX  - mWorldXMin) + mViewXMin);
		float temp = mWorldYMax - (pt.mY * mWorldYMax);
		retPt.mY = (int) (( (mViewYMax - mViewYMin) / (mWorldYMax - mWorldYMin) ) * (temp  - mWorldYMin) + mViewYMin);
		
		return retPt;
	}
	
	/**
	 * Convert rectangle value in world to view which is in quadrant 1 - x increasing left, y increasing up
	 * @param worldX
	 * @return
	 */
	public RectInt convertToViewQuadrant1(RectFloat world)
	{
		RectInt ret = new RectInt();
		
		ret.left = (int) (( (mViewXMax - mViewXMin) / (mWorldXMax - mWorldXMin) ) * (world.left  - mWorldXMin) + mViewXMin);
		float temp = mWorldYMax - (world.top * mWorldYMax);
		ret.top = (int) (( (mViewYMax - mViewYMin) / (mWorldYMax - mWorldYMin) ) * (temp - mWorldYMin) + mViewYMin);
		
		ret.right = (int) (( (mViewXMax - mViewXMin) / (mWorldXMax - mWorldXMin) ) * (world.right  - mWorldXMin) + mViewXMin);
		temp = mWorldYMax - (world.bottom * mWorldYMax);
		ret.bottom = (int) (( (mViewYMax - mViewYMin) / (mWorldYMax - mWorldYMin) ) * (temp - mWorldYMin) + mViewYMin);
		
		return ret;
	}
	
	/**
	 * Convert x coordinate value in view to world which is in quadrant 1 - x increasing left, y increasing up
	 * @param viewX
	 * @return
	 */
	public float convertToWorldXQuadrant1(int viewX)
	{
		float retVal = 0;
		
		retVal = (( (mWorldXMax - mWorldXMin) / (mViewXMax - mViewXMin) ) * (viewX  - mViewXMin) + mWorldXMin);
		
		return retVal;
	}
	
	/**
	 * Convert y coordinate value in view to world which is in quadrant 1 - x increasing left, y increasing up
	 * @param viewX
	 * @return
	 */
	public float convertToWorldYQuadrant1(int viewY)
	{
		float retVal = 0;
		
		retVal = (( (mWorldYMax - mWorldYMin) / (mViewYMax - mViewYMin) ) * (viewY  - mViewYMin) + mWorldYMin);
		
		return retVal;
	}
	
	/**
	 * Convert 2d point value in view to world which is in quadrant 1 - x increasing left, y increasing up
	 * @param viewX
	 * @return
	 */
	public Point2DFloat convertToWorldQuadrant1(int viewX, int viewY)
	{
		Point2DFloat retPt = new Point2DFloat();
		
		retPt.mX = (( (mWorldXMax - mWorldXMin) / (mViewXMax - mViewXMin) ) * (viewX  - mViewXMin) + mWorldXMin);
		retPt.mY = (( (mWorldYMax - mWorldYMin) / (mViewYMax - mViewYMin) ) * (viewY  - mViewYMin) + mWorldYMin);
		
		return retPt;
	}
	
	/**
	 * Convert 2d coordinate value in view to world which is in quadrant 1 - x increasing left, y increasing up
	 * @param viewX
	 * @return
	 */
	public Point2DFloat convertToWorldQuadrant1(Point2DInt pt)
	{
		Point2DFloat retPt = new Point2DFloat();
		
		retPt.mX = (( (mWorldXMax - mWorldXMin) / (mViewXMax - mViewXMin) ) * (pt.mX  - mViewXMin) + mWorldXMin);
		retPt.mY = (( (mWorldYMax - mWorldYMin) / (mViewYMax - mViewYMin) ) * (pt.mY  - mViewYMin) + mWorldYMin);
		
		return retPt;
	}
}

/* end */
